#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <optional>
#include <set>
#include <limits>
#include <algorithm>
#include <istream>
#include <fstream>

// GLFW_INCLUDE_VULKAN是预处理宏，用于在使用GLFW和Vulkan时，自动包含Vulkan的头文件
#define GLFW_INCLUDE_VULKAN
// glfw/glfw3.h是GLFW库的头文件，提供了在C或C++中使用的GLFW的接口
#include <glfw/glfw3.h>

const std::string pipelineCachePath = "Cache/pipelineConfig.config";

// NDEBUG是预处理宏，用于在编译时控制代码的调试和发布版本之间的差异
#ifdef NDEBUG
	const bool enabledValidationLayer = false;
#else
	const bool enabledValidationLayer = true;
#endif

/*
VK_LAYER_KHRONOS_validation 综合性验证层，包含多种验证功能，是开发阶段的首选
VK_LAYER_LUNARG_core_validation 专注于核心API的验证
VK_LAYER_LUNARG_object_tracker 跟踪对象的创建和销毁，检测资源泄露
VK_LAYER_LUNARG_parameter_validation 验证API参数的合法性
VK_LAYER_LUNARG_swapchain 验证交换链相关操作
VK_LAYER_LUNARG_threading 检查多线程环境下的API使用
*/

const std::vector<const char*> LayerNames = {
	"VK_LAYER_KHRONOS_validation"
};

// 应用程序（比如游戏或应用）需要用到交换链中的图像来进行渲染，应用程序控制图像，称为“拥有”图像；
// 渲染完成，图像就需要提交给显示器（通过交换链）来展示，图像的“所有权”就交给了显示硬件（显示器或GPU）
const std::vector<const char*> deviceExtensions = {
	VK_KHR_SWAPCHAIN_EXTENSION_NAME
};

struct windowInfo {
	int width;
	int height;
	std::string title;
};

struct queueFamily {
	std::optional<uint32_t> graphicsQueueFamily;
	std::optional<uint32_t> presentQueueFamily;
	bool isComplete() {
		return 
			graphicsQueueFamily.has_value() && 
			presentQueueFamily.has_value();
	}
};

struct SwapChainDetails {
	// VkSurfaceCapabilitiesKHR描述与某个表面相关的能力和特性
	// supportedUsageFlags 支持的使用标志
  // minImageCount 最小图像数量
  // maxImageCount 最大图像数量
  // currentExtent[2] 当前图像的宽高
  // minImageExtent[2] 图像的最小尺寸
  // maxImageExtent[2] 图像的最大尺寸
  // maxImageArrayLayers 最大图像数组层数
  // supportedTransforms 支持的转换（旋转、翻转等）
  // supportedCompositeAlpha 支持的复合透明度
  // supportedUsageFlags 支持的图像用法（渲染目标、显示等）
	VkSurfaceCapabilitiesKHR cap;
	// VkSurfaceFormatKHR描述表面支持的图像格式及其颜色空间
	// format 图像格式
	// VK_FORMAT_R8G8B8A8_UNORM 每个颜色通道8位，无符号整数，表示红、绿、蓝、透明度（RGBA），常用于2D渲染和纹理
	// VK_FORMAT_B8G8R8A8_UNORM 与VK_FORMAT_R8G8B8A8_UNORM相似，只是颜色通道的顺序为BGRA，常用于Windows系统的图形API
	// VK_FORMAT_R32G32B32A32_SFLOAT 每个通道32位，浮点数格式，用于高精度的颜色存储和计算
	// VK_FORMAT_B8G8R8A8_SRGB 与VK_FORMAT_B8G8R8A8_UNORM相似，但使用了sRGB色彩空间，适用于显示设备
	// colorSpace 颜色空间
	// VK_COLOR_SPACE_SRGB_NONLINEAR_KHR 标准RGB非线性色彩空间（sRGB）
  // VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_KHR DisplayP3非线性色彩空间
  // VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_KHR 扩展的sRGB线性色彩空间
  // VK_COLOR_SPACE_DCI_P3_NONLINEAR_KHR DCI-P3非线性色彩空间（电影标准）
  // VK_COLOR_SPACE_BT709_NONLINEAR_KHR BT.709非线性色彩空间
  // VK_COLOR_SPACE_ADOBERGB_LINEAR_KHR AdobeRGB线性色彩空间
  // VK_COLOR_SPACE_BT2020_LINEAR_KHR BT.2020线性色彩空间（适用于4K UHD）
  // VK_COLOR_SPACE_HDR10_ST2084_KHR HDR10（ST 2084）色彩空间
  // VK_COLOR_SPACE_DOLBYVISION_KHR Dolby Vision色彩空间
  // VK_COLOR_SPACE_HDR10_HLG_KHR HDR10 HLG色彩空间（Hybrid Log-Gamma）
  // VK_COLOR_SPACE_ADOBERGB_NONLINEAR_KHR Adobe RGB非线性色彩空间
  // VK_COLOR_SPACE_SCRGB_LINEAR_KHR scRGB线性色彩空间
	std::vector<VkSurfaceFormatKHR> formats;
	// VkPresentModeKHR用于描述图像呈现模式的枚举类型
	// VK_PRESENT_MODE_IMMEDIATE_KHR 立即模式，最简单但可能导致画面撕裂
  // VK_PRESENT_MODE_MAILBOX_KHR 邮箱模式，用于避免画面撕裂，带有低延迟
  // VK_PRESENT_MODE_FENCE_KHR 高效的等待模式，主要用于离屏渲染
  // VK_PRESENT_MODE_FIFO_KHR FIFO模式，最常用的模式，保证图像按顺序呈现
  // VK_PRESENT_MODE_FIFO_RELAXED_KHR 松弛FIFO模式，提供稍微的灵活性
	std::vector<VkPresentModeKHR> modes;
};

class test {
public:
	test();
	test(windowInfo window_info);
	~test();
public:
	void run();
private:
	void initWindow();
	void initVulkan();
	void createInstance();
	bool checkValidationLayerSupport();
	void setupMessenger();
	// VkDebuUtilsMessengerCreateInfoEXT用于创建调试信息监听器的结构体
	// sType 结构体标识
	// messageSeverity 指定调试信息的严重性级别
	// messageType 指定调试信息的类别
	// pfnUserCallback 指向用于定义的回调函数的指针
	// pUserData 将用于自定义数据传递给回调函数
	void populateDebugUtilsMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& debugUtilsMessenger);
	VkResult createDebugUtilsMessenger(
		VkInstance c_instance, 
		VkDebugUtilsMessengerCreateInfoEXT* c_createInfo, 
		// VkAllocationCallbacks用于内存分配和释放的回调结构体
		VkAllocationCallbacks* c_allocation, 
		VkDebugUtilsMessengerEXT* c_debugMessenger);
	void destroyDebugUtilsMessenger(
		VkInstance c_instance, 
		VkDebugUtilsMessengerEXT c_debugMessenger, 
		VkAllocationCallbacks* c_allocation);
	void pickupPhysicalDevice();
	void createSurface();
	queueFamily findQueueFamilyIndex(VkPhysicalDevice c_device);
	void createLogicDevice();
	bool isDeviceSuitable(VkPhysicalDevice c_device);
	bool checkDeviceExtensionSupported(VkPhysicalDevice c_device);
	SwapChainDetails querySwapChainSupport(VkPhysicalDevice c_device);
	VkSurfaceCapabilitiesKHR GetSurfaceCap(VkPhysicalDevice c_device);
	std::vector<VkSurfaceFormatKHR> GetSurfaceFmt(VkPhysicalDevice c_device);
	std::vector<VkPresentModeKHR> GetSurfacePM(VkPhysicalDevice c_device);
	VkSurfaceFormatKHR chooseSurfaceFmt(const SwapChainDetails& details);
	VkPresentModeKHR choosePresentMode(const SwapChainDetails& details);
	// VkExtent2D表示二维图像、表面、窗口或交换链等的尺寸
	VkExtent2D chooseExtent2D(const SwapChainDetails& details);
	// VkShaderModule用于封装着色器代码的对象，代表一个着色器模块
	VkShaderModule createShaderModule(const std::vector<char>& code);	void createSwapChain();
	void GetSwapChainImage(std::vector<VkImage>& images);
	void createImageView();
	void createRenderPass();
	void createGraphicsPipeline();
	void createCommandPool();
	void createCommandBuffers();
	// VkCommandBuffer就是GPU指令录制缓冲区，把所有绘制、计算、资源过渡等命令写进去，最后一次性交给GPU去执行
	// VkCommandBufferUsageFlags用于控制命令缓冲区在记录时的使用行为，标志直接影响命令缓冲区的生命周期、可重用性，以及在执行时Vulkan驱动如何优化它
	// VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT（命令缓冲区只会提交一次）、
	// VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT（命令缓冲区必须在某个RenderPass的某个Subpass内执行，通常是二级命令缓冲区的标志）、
	// VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT（允许一个命令缓冲区同时被多个vkQueueSubmit使用，并且GPU上的多个提交可能并行执行它）
	void beginCommandBuffer(VkCommandBuffer& readyCommandBuffer, VkCommandBufferUsageFlags flags);
	void endCommandBuffer(VkCommandBuffer& readyCommandBuffer);
	void recordCommandBuffer(VkCommandBuffer&	recordCommandBuffer, uint32_t imageIndex);
	void drawFrame();
private:
	void createFrameBuffers();
private:
	static std::vector<char> readFile(const std::string& filePath);
	static void writeFile(const std::string& filePath, std::vector<char> data, size_t dataSize);
private:
	// VKAPI_ATTR表示该函数使用Vulkan的特定调用约定
	// VKAPI_CALL指示编译器使用正确的调用约定
	static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
		// VkDebugUtilsMessageSeverityFlagBitsEXT用于调试信息严重性级别的一个标志位类型，定义了Vulkan调试信息的严重程度
		VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, 
		// VkDebugUtilsMessageTypeFlagsEXT用于描述调试信息的类型
		VkDebugUtilsMessageTypeFlagsEXT messageType, 
		// VkDebugUtilsMessengerCallbackDataEXT用于存储调试信息的详细数据
		const VkDebugUtilsMessengerCallbackDataEXT* messengerData, 
		// 指向用户数据的指针
		void* pUserData
	);

private:
	void cleanupWindow();
	void cleanupVulkan();
	void cleanupAll();
private:
	windowInfo w_info;
	GLFWwindow* window;
	// VkInstance是核心对象，代表了Vulkan实例，它是与整个Vulkan环境交互的起点
	VkInstance instance;
	// VkDebugUtilsMessengerEXT用于提供调试信息和回调功能
	VkDebugUtilsMessengerEXT debugMessenger;
	// VkPhysicalDevice用于表示物理设备（GPU）对象
	VkPhysicalDevice device;
	// VkDevice表示与物理设备（GPU）交互的逻辑设备
	VkDevice logicDevice;
	// VkQueue表示物理设备（GPU）队列，用于提交命令到物理设备（GPU）进行执行
	VkQueue graphicsQueue;
	VkQueue	presentQueue;
	// VkSurfaceKHR表示与窗口系统或屏幕的关联的句柄
	VkSurfaceKHR surface;
	// VkSwapchainKHR用于管理和呈现图像交换链的对象
	VkSwapchainKHR swapChain;
	// VkFormat用于指定图像、缓冲区或其他资源的数据格式
	VkFormat swapChainImageFormat;
	VkExtent2D swapChainImageExtent;
	// VkPipelineLayout表示与渲染管线关联的资源布局配置的对象
	VkPipelineLayout pipelineLayout;
	// VkRenderPass用于描述一组渲染操作和这些操作对帧缓冲附件的使用方式，其实就是GPU如何访问和操作帧缓冲里的存储单元
	VkRenderPass renderPass;
	// VkPipeline是渲染状态的封装，定义了GPU渲染或计算的全部行为
	VkPipeline graphicsPipeline;
	// VkCommandPool用于管理和分配命令缓冲区的对象
	VkCommandPool commandPool;
	// VkCommandBuffer用于存储并记录GPU命令的对象
	VkCommandBuffer commandBuffer;
private:
	// VkFramebuffer用于描述渲染过程中使用的附件，提供了一个抽象，表示一组图像对象，图像在渲染过程中作为输出目标被使用
	std::vector<VkFramebuffer> swapChainFrameBuffers;
	// VkImage用来存储图像数据的资源对象
	std::vector<VkImage> swapChainImages;
	// VkImageView用于以特定的方式访问图像的对象
	std::vector<VkImageView> imageViews;
private:
	queueFamily q_Family;
};
